home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / pt-mat.cc < prev    next >
C/C++ Source or Header  |  1997-01-08  |  13KB  |  639 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. #if defined (__GNUG__)
  24. #pragma implementation
  25. #endif
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include <config.h>
  29. #endif
  30.  
  31. #include <iostream.h>
  32. #include <strstream.h>
  33.  
  34. #include "defun.h"
  35. #include "error.h"
  36. #include "oct-obj.h"
  37. #include "pt-exp.h"
  38. #include "pt-fvc.h"
  39. #include "pt-mat.h"
  40. #include "pt-misc.h"
  41. #include "pt-mvr.h"
  42. #include "pt-walk.h"
  43. #include "utils.h"
  44. #include "ov.h"
  45. #include "variables.h"
  46.  
  47. // Are empty elements in a matrix list ok?  For example, is the empty
  48. // matrix in an expression like `[[], 1]' ok?  A positive value means
  49. // yes.  A negative value means yes, but print a warning message.
  50. // Zero means it should be considered an error.
  51. static int Vempty_list_elements_ok;
  52.  
  53. // The character to fill with when creating string arrays.
  54. static char Vstring_fill_char;
  55.  
  56. // General matrices.  This list type is much more work to handle than
  57. // constant matrices, but it allows us to construct matrices from
  58. // other matrices, variables, and functions.
  59.  
  60. // But first, some internal classes that make our job much easier.
  61.  
  62. class
  63. tm_row_const
  64. {
  65. private:
  66.  
  67.   class
  68.   tm_row_const_rep : public SLList<octave_value>
  69.   {
  70.   public:
  71.  
  72.     tm_row_const_rep (void)
  73.       : SLList<octave_value> (), count (1), nr (0), nc (0),
  74.     all_str (false), is_cmplx (false), all_mt (true), ok (false) { }
  75.  
  76.     tm_row_const_rep (const tree_matrix_row& mr)
  77.       : SLList<octave_value> (), count (1), nr (0), nc (0),
  78.     all_str (false), is_cmplx (false), all_mt (true), ok (false)
  79.         { init (mr); }
  80.  
  81.     ~tm_row_const_rep (void) { }
  82.  
  83.     int count;
  84.  
  85.     int nr;
  86.     int nc;
  87.  
  88.     bool all_str;
  89.     bool is_cmplx;
  90.     bool all_mt;
  91.  
  92.     bool ok;
  93.  
  94.     void init (const tree_matrix_row&);
  95.  
  96.   private:
  97.  
  98.     tm_row_const_rep (const tm_row_const_rep&);
  99.  
  100.     tm_row_const_rep& operator =
  101.       (const tm_row_const_rep&);
  102.  
  103.  
  104.     void eval_error (const char *msg, int l, int c) const;
  105.  
  106.     void eval_warning (const char *msg, int l, int c) const;
  107.   };
  108.  
  109. public:
  110.  
  111.   tm_row_const (void) : rep (0) { }
  112.  
  113.   tm_row_const (const tree_matrix_row& mr)
  114.     : rep (new tm_row_const_rep (mr)) { }
  115.  
  116.   tm_row_const (const tm_row_const& x) : rep (x.rep)
  117.     {
  118.       if (rep)
  119.     rep->count++;
  120.     }
  121.  
  122.   tm_row_const& operator = (const tm_row_const& x)
  123.     {
  124.       if (this != &x && rep != x.rep)
  125.     {
  126.       if (rep && --rep->count == 0)
  127.         delete rep;
  128.  
  129.       rep = x.rep;
  130.  
  131.       if (rep)
  132.         rep->count++;
  133.     }
  134.  
  135.       return *this;
  136.     }
  137.  
  138.   ~tm_row_const (void)
  139.     {
  140.       if (rep && --rep->count == 0)
  141.     delete rep;
  142.     }
  143.  
  144.   int rows (void) { return rep->nr; }
  145.   int cols (void) { return rep->nc; }
  146.  
  147.   bool all_strings (void) const { return rep->all_str; }
  148.   bool is_complex (void) const { return rep->is_cmplx; }
  149.   bool all_empty (void) const { return rep->all_mt; }
  150.  
  151.   octave_value& operator () (Pix p) { return rep->operator () (p); }
  152.  
  153.   const octave_value& operator () (Pix p) const
  154.     { return rep->operator () (p); }
  155.  
  156.   Pix first (void) const { return rep->first (); }
  157.   void next (Pix& p) const { rep->next (p); }
  158.   
  159.   operator void* () const
  160.     {
  161.       return (rep && rep->ok) ? (void *) -1 : (void *) 0;
  162.     }
  163.  
  164. private:
  165.  
  166.   tm_row_const_rep *rep;
  167. };
  168.  
  169. void
  170. tm_row_const::tm_row_const_rep::init (const tree_matrix_row& mr)
  171. {
  172.   all_str = true;
  173.  
  174.   bool first_elem = true;
  175.  
  176.   for (Pix p = mr.first (); p != 0; mr.next (p))
  177.     {
  178.       tree_expression *elt = mr (p);
  179.  
  180.       octave_value tmp = elt->eval (false);
  181.  
  182.       if (error_state || tmp.is_undefined ())
  183.     break;
  184.       else
  185.     {
  186.       int this_elt_nr = tmp.rows ();
  187.       int this_elt_nc = tmp.columns ();
  188.  
  189.       if (this_elt_nr == 0 || this_elt_nc == 0)
  190.         {
  191.           if (Vempty_list_elements_ok < 0)
  192.         eval_warning ("empty matrix found in matrix list",
  193.                   elt->line (), elt->column ());
  194.           else if (Vempty_list_elements_ok == 0)
  195.         {
  196.           eval_error ("empty matrix found in matrix list",
  197.                   elt->line (), elt->column ());
  198.           break;
  199.         }
  200.         }
  201.       else
  202.         {
  203.           all_mt = false;
  204.  
  205.           if (first_elem)
  206.         {
  207.           first_elem = false;
  208.  
  209.           nr = this_elt_nr;
  210.         }
  211.           else if (this_elt_nr != nr)
  212.         {
  213.           eval_error ("number of rows must match",
  214.                   elt->line (), elt->column ());
  215.           break;
  216.         }
  217.  
  218.           nc += this_elt_nc;
  219.  
  220.           append (tmp);
  221.         }
  222.  
  223.       if (all_str && ! tmp.is_string ())
  224.         all_str = false;
  225.  
  226.       if (! is_cmplx && tmp.is_complex_type ())
  227.         is_cmplx = true;
  228.     }
  229.     }
  230.  
  231.   ok = ! error_state;
  232. }
  233.  
  234. void
  235. tm_row_const::tm_row_const_rep::eval_error (const char *msg, int l,
  236.                         int c) const
  237. {
  238.   if (l == -1 && c == -1)
  239.     ::error ("%s", msg);
  240.   else
  241.     ::error ("%s near line %d, column %d", msg, l, c);
  242. }
  243.  
  244. void
  245. tm_row_const::tm_row_const_rep::eval_warning (const char *msg, int l,
  246.                           int c) const
  247. {
  248.   if (l == -1 && c == -1)
  249.     ::warning ("%s", msg);
  250.   else
  251.     ::warning ("%s near line %d, column %d", msg, l, c);
  252. }
  253.  
  254. #include "SLList.h"
  255. #include "SLList.cc"
  256.  
  257. template class SLNode<tm_row_const>;
  258. template class SLList<tm_row_const>;
  259.  
  260. class
  261. tm_const : public SLList<tm_row_const>
  262. {
  263. public:
  264.  
  265.   tm_const (const tree_matrix& tm)
  266.     : SLList<tm_row_const> (), nr (0), nc (0), all_str (false),
  267.       is_cmplx (false), all_mt (true), ok (false)
  268.       { init (tm); }
  269.  
  270.   ~tm_const (void) { }
  271.  
  272.   int rows (void) const { return nr; }
  273.   int cols (void) const { return nc; }
  274.  
  275.   bool all_strings (void) const { return all_str; }
  276.   bool is_complex (void) const { return is_cmplx; }
  277.   bool all_empty (void) const { return all_mt; }
  278.  
  279.   operator void* () const { return ok ? (void *) -1 : (void *) 0; }
  280.  
  281. private:
  282.  
  283.   int nr;
  284.   int nc;
  285.  
  286.   bool all_str;
  287.   bool is_cmplx;
  288.   bool all_mt;
  289.  
  290.   bool ok;
  291.  
  292.   tm_const (void);
  293.  
  294.   tm_const (const tm_const&);
  295.  
  296.   tm_const& operator = (const tm_const&);
  297.  
  298.   void init (const tree_matrix& tm);
  299. };
  300.  
  301. void
  302. tm_const::init (const tree_matrix& tm)
  303. {
  304.   all_str = true;
  305.  
  306.   bool first_elem = true;
  307.  
  308.   // Just eval and figure out if what we have is complex or all
  309.   // strings.  We can't check columns until we know that this is a
  310.   // numeric matrix -- collections of strings can have elements of
  311.   // different lengths.
  312.  
  313.   for (Pix p = tm.first (); p != 0; tm.next (p))
  314.     {
  315.       tree_matrix_row *elt = tm (p);
  316.  
  317.       tm_row_const tmp (*elt);
  318.  
  319.       if (tmp)
  320.     {
  321.       if (all_str && ! tmp.all_strings ())
  322.         all_str = false;
  323.  
  324.       if (! is_cmplx && tmp.is_complex ())
  325.         is_cmplx = true;
  326.  
  327.       if (all_mt && ! tmp.all_empty ())
  328.         all_mt = false;
  329.  
  330.       append (tmp);
  331.     }
  332.       else
  333.     break;
  334.     }
  335.  
  336.   if (! error_state)
  337.     {
  338.       for (Pix p = first (); p != 0; next (p))
  339.     {
  340.       tm_row_const elt = this->operator () (p);
  341.  
  342.       int this_elt_nr = elt.rows ();
  343.       int this_elt_nc = elt.cols ();
  344.  
  345.       if (this_elt_nr == 0 || this_elt_nc == 0)
  346.         {
  347.           if (Vempty_list_elements_ok < 0)
  348.         warning ("empty matrix found in matrix list");
  349.           else if (Vempty_list_elements_ok == 0)
  350.         {
  351.           ::error ("empty matrix found in matrix list");
  352.           break;
  353.         }
  354.         }
  355.       else
  356.         {
  357.           all_mt = false;
  358.  
  359.           if (first_elem)
  360.         {
  361.           first_elem = false;
  362.  
  363.           nc = this_elt_nc;
  364.         }
  365.           else if (all_str)
  366.         {
  367.           if (this_elt_nc > nc)
  368.             nc = this_elt_nc;
  369.         }
  370.           else if (this_elt_nc != nc)
  371.         {
  372.           ::error ("number of columns must match");
  373.           break;
  374.         }
  375.  
  376.           nr += this_elt_nr;
  377.         }
  378.     }
  379.     }
  380.  
  381.   ok = ! error_state;
  382. }
  383.  
  384. bool
  385. tree_matrix_row::all_elements_are_constant (void) const
  386. {
  387.   for (Pix p = first (); p != 0; next (p))
  388.     {
  389.       tree_expression *elt = this->operator () (p);
  390.  
  391.       if (! elt->is_constant ())
  392.     return false;
  393.     }
  394.  
  395.   return true;
  396. }
  397.  
  398. tree_return_list *
  399. tree_matrix_row::to_return_list (void)
  400. {
  401.   tree_return_list *retval = 0;
  402.  
  403.   bool first_elem = true;
  404.  
  405.   for (Pix p = first (); p != 0; next (p))
  406.     {
  407.       tree_expression *elt = this->operator () (p);
  408.  
  409.       bool is_id = elt->is_identifier ();
  410.  
  411.       bool is_idx_expr = elt->is_index_expression ();
  412.  
  413.       if (is_id || is_idx_expr)
  414.     {
  415.       tree_index_expression *idx_expr;
  416.  
  417.       if (is_id)
  418.         {
  419.           tree_identifier *id = (tree_identifier *) elt;
  420.           idx_expr = new tree_index_expression (id);
  421.         }
  422.       else
  423.         idx_expr = (tree_index_expression *) elt;
  424.  
  425.       if (first_elem)
  426.         {
  427.           first_elem = false;
  428.  
  429.           retval = new tree_return_list (idx_expr);
  430.         }
  431.       else
  432.         retval->append (idx_expr);
  433.     }
  434.       else
  435.     {
  436.       delete retval;
  437.       retval = 0;
  438.       break;
  439.     }
  440.     }
  441.  
  442.   return retval;
  443. }
  444.  
  445. void
  446. tree_matrix_row::accept (tree_walker& tw)
  447. {
  448.   tw.visit_matrix_row (*this);
  449. }
  450.  
  451. bool
  452. tree_matrix::all_elements_are_constant (void) const
  453. {
  454.   for (Pix p = first (); p != 0; next (p))
  455.     {
  456.       tree_matrix_row *elt = this->operator () (p);
  457.  
  458.       if (! elt->all_elements_are_constant ())
  459.     return false;
  460.     }
  461.  
  462.   return true;
  463. }
  464.  
  465. // Just about as ugly as it gets.
  466. // Less ugly than before, anyway.
  467. // Looking better all the time.
  468.  
  469. octave_value
  470. tree_matrix::eval (bool /* print */)
  471. {
  472.   octave_value retval;
  473.  
  474.   tm_const tmp (*this);
  475.  
  476.   bool all_strings = false;
  477.   bool all_empty = false;
  478.  
  479.   if (tmp)
  480.     {
  481.       int nr = tmp.rows ();
  482.       int nc = tmp.cols ();
  483.  
  484.       Matrix m;
  485.       ComplexMatrix cm;
  486.       charMatrix chm;
  487.  
  488.       // Now, extract the values from the individual elements and
  489.       // insert them in the result matrix.
  490.  
  491.       bool found_complex = tmp.is_complex ();
  492.  
  493.       all_strings = tmp.all_strings ();
  494.       all_empty = tmp.all_empty ();
  495.  
  496.       if (all_strings)
  497.     chm.resize (nr, nc, Vstring_fill_char);
  498.       else if (found_complex)
  499.     cm.resize (nr, nc, 0.0);
  500.       else
  501.     m.resize (nr, nc, 0.0);
  502.  
  503.       int put_row = 0;
  504.  
  505.       for (Pix p = tmp.first (); p != 0; tmp.next (p))
  506.     {
  507.       int put_col = 0;
  508.  
  509.       tm_row_const row = tmp (p);
  510.  
  511.       for (Pix q = row.first (); q != 0; row.next (q))
  512.         {
  513.           octave_value elt = row (q);
  514.  
  515.           if (found_complex)
  516.         {
  517.           if (elt.is_real_scalar ())
  518.             cm (put_row, put_col) = elt.double_value ();
  519.           else if (elt.is_real_matrix () || elt.is_range ())
  520.             cm.insert (elt.matrix_value (), put_row, put_col);
  521.           else if (elt.is_complex_scalar ())
  522.             cm (put_row, put_col) = elt.complex_value ();
  523.           else
  524.             {
  525.               ComplexMatrix cm_elt = elt.complex_matrix_value ();
  526.  
  527.               if (error_state)
  528.             goto done;
  529.  
  530.               cm.insert (cm_elt, put_row, put_col);
  531.             }
  532.         }
  533.           else
  534.         {
  535.           if (elt.is_real_scalar ())
  536.             m (put_row, put_col) = elt.double_value ();
  537.           else if (elt.is_string () && all_strings)
  538.             {
  539.               charMatrix chm_elt = elt.char_matrix_value ();
  540.  
  541.               if (error_state)
  542.             goto done;
  543.  
  544.               chm.insert (chm_elt, put_row, put_col);
  545.             }
  546.           else
  547.             {
  548.               Matrix m_elt = elt.matrix_value ();
  549.  
  550.               if (error_state)
  551.             goto done;
  552.  
  553.               m.insert (m_elt, put_row, put_col);
  554.             }
  555.         }
  556.  
  557.           if (all_strings && chm.rows () > 0 && chm.cols () > 0)
  558.         retval = octave_value (chm, true);
  559.           else if (found_complex)
  560.         retval = cm;
  561.           else
  562.         retval = m;
  563.  
  564.           put_col += elt.columns ();
  565.         }
  566.  
  567.       put_row += row.rows ();
  568.     }
  569.     }
  570.  
  571. done:
  572.  
  573.   if (! error_state && retval.is_undefined () && all_empty)
  574.     {
  575.       if (all_strings)
  576.     retval = "";
  577.       else
  578.     retval = Matrix ();
  579.     }
  580.  
  581.   return retval;
  582. }
  583.  
  584. void
  585. tree_matrix::accept (tree_walker& tw)
  586. {
  587.   tw.visit_matrix (*this);
  588. }
  589.  
  590. static int
  591. empty_list_elements_ok (void)
  592. {
  593.   Vempty_list_elements_ok = check_preference ("empty_list_elements_ok");
  594.  
  595.   return 0;
  596. }
  597.  
  598. static int
  599. string_fill_char (void)
  600. {
  601.   int status = 0;
  602.  
  603.   string s = builtin_string_variable ("string_fill_char");
  604.  
  605.   switch (s.length ())
  606.     {
  607.     case 1:
  608.       Vstring_fill_char = s[0];
  609.       break;
  610.  
  611.     case 0:
  612.       Vstring_fill_char = '\0';
  613.       break;
  614.  
  615.     default:
  616.       warning ("string_fill_char must be a single character");
  617.       status = -1;
  618.       break;
  619.     }
  620.  
  621.   return status;
  622. }
  623.  
  624. void
  625. symbols_of_pt_mat (void)
  626. {
  627.   DEFVAR (empty_list_elements_ok, "warn", 0, empty_list_elements_ok,
  628.     "ignore the empty element in expressions like `a = [[], 1]'");
  629.  
  630.   DEFVAR (string_fill_char, " ", 0, string_fill_char,
  631.     "the character to fill with when creating string arrays.");
  632. }
  633.  
  634. /*
  635. ;;; Local Variables: ***
  636. ;;; mode: C++ ***
  637. ;;; End: ***
  638. */
  639.